import {
    BroadcastRequest,
    BroadcastResponse,
    BroadcastResponseStatus,
    BroadcastType,
    Controller,
    ControllerNo,
    ControllerOpt,
    DialogControllerOpt
} from "./model/ControllerOpt";
import {Attrs, BuffInfo, CaluAttrStr, CaluType, ColorStr, LearnSkillFailed} from "../type/Type";
import {DataRouter} from "../frame/dataSource/DataRouter";
import {Util} from "../utils/Util";
import {ControllerBroadcast} from "./ControllerBroadcast";
import {DataRouterUtil} from "../utils/router/DataRouterUtil";
import {GlobalEnv} from "../utils/GlobalEnv";
import {AbilitySerializeBody, SerializeBody, SerializeLoadType} from "./model/SerializeBody";
import {AbilityEffectData, AttributeEnum, UnitAttribute} from "../frame/dataSource/DataModel";
import {DialogController} from "./DialogController";
import {ConfigKey} from "../constant/ConfigConstant";
import Configer from "../frame/apiModel/config/Configer";
import {FinalKey} from "../constant/FinalConstant";
import {Logger} from "../frame/apiModel/config/Logger";
import {UnitModel} from "../frame/apiModel/adapterModel/model3/UnitModel";
import {PlayerFactory} from "../frame/PlayerFactory";
import {PlayerDataKey, UnitDataKey} from "../frame/dataSource/DataSource";
import {PlayerModel} from "../frame/apiModel/adapterModel/model4/PlayerModel";
import {AbilityJson} from "../frame/apiModel/model/StoreJson";
import {CodeUtil} from "../frame/codeAdapter/CodeUtil";
import {ModelFactory} from "../frame/apiModel/adapterModel/model5/ModelFactory";
import {AbilityModel} from "./model/AbilityModel";
import {ItemModel} from "../frame/apiModel/adapterModel/model3/ItemModel";
import {LocModel} from "../frame/apiModel/base/LocModel";
import {ModelType} from "../frame/apiModel/adapter/adapterInterface/model5/IModelFactory";
import MathUtil from "../frame/codeAdapter/MathUtil";

export class AbilityController implements Controller {
    getControllerNo(): number {
        return ControllerNo.AbilityController;
    }

    private static abilityController: AbilityController = new AbilityController();

    private attributeUnitMaps: {[key: string]: { [effectId: string]: number } } = {}
    private abilityLockUnitMaps: {[key: string]: { [effectId: string]: number } } = {}
    private abilityMaps: {[key: string]: AbilityModel } = {}

    static getInstance() {
        return AbilityController.abilityController;
    }
    init() {
        ControllerBroadcast.getInstance().startListen(AbilityController.getInstance());
    }
    loadByJson(json: AbilitySerializeBody, player: PlayerModel) {
        const unit = GlobalEnv.getHero(player);
        if (unit?.isValid()) {
            const archiveIndex = player.data[PlayerDataKey.archiveIndex];
            this.mapAbilitySerialize(archiveIndex, SerializeLoadType.current_global, (key, index, hotKey) => {
                const ability: AbilityJson = json[key];
                if (!CodeUtil.isNullOrZero(ability)) {
                    const abilityId = ability.id;
                    AbilityController.getInstance().learnAbility(unit, abilityId, 1);
                }
            })
        }
    }

    registAbilityModel(abilityModel: AbilityModel) {
        this.abilityMaps[abilityModel.abilityId] = abilityModel;
    }

    useAbilityModelByAbilityId(activeUnit: UnitModel, activeItem: ItemModel, targetUnit: UnitModel, targetItem: ItemModel, activePlayer: PlayerModel, targetPlayer: PlayerModel, spellId: string, spellLoc: LocModel) {
        let bUse = false;
        let success = true;
        const abilityModel = this.abilityMaps[spellId];
        if (abilityModel) {
            bUse = true;
            success = abilityModel.actionFun(activeUnit, activeItem, targetUnit, targetItem, activePlayer, targetPlayer, spellId, spellLoc);
        }
        return { bUse, success };
    }

    learnAbilityCheck (unit: UnitModel, abilityId: string) {
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        const learnSkillFailed = this.recordAbility(unit, abilityId);
        switch (learnSkillFailed) {
            case LearnSkillFailed.autoLearn:{
                Logger.toastProduct(`您已经学会了这个技能`, player)
                return false;
            }
            case LearnSkillFailed.overMax:{
                const skillHotKey: string[] = Configer.getFinal(FinalKey.skillHotKeys);
                const maxAbilityNum = skillHotKey.length;
                Logger.toastProduct(`您最多只能学习${maxAbilityNum}个技能!`, player);
                return false;
            }
            case LearnSkillFailed.isNull:{
                Logger.toastError(`学习技能Id不能为空, 请联系作者!`);
                return false;
            }
        }
        this.learnAbility(unit, abilityId, 1);
        return true;

    }
    loseAbilityByFamilyIdCheck (unit: UnitModel, familyId: string, targetLevel?: number) {
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        if (familyId) {
            const ret = DataRouterUtil.getUnitAbilityIdByFamilyId(unit, familyId);
            // 如果有其他本家族技能 移除掉旧技能
            const oldAbilityId = ret.id
            const oldLv = ret.lv
            if (oldAbilityId) {
                if (oldLv === targetLevel) {
                    this.loseAbility(unit, oldAbilityId);
                }
                return true;
            } else {
                Logger.toastProduct(`没有目标技能 ${familyId} ${targetLevel}`, player, ColorStr.red);
                return false;
            }
        } else {
            Logger.toastError(`请传入正确的技能家族`);
        }
    }
    learnAbilityByFamilyIdCheck (unit: UnitModel, familyId: string, targetLevel?: number) {
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        if (familyId) {
            const ret = DataRouterUtil.getUnitAbilityIdByFamilyId(unit, familyId);

            const lv = ret.lv;
            if (targetLevel) {
                const fontLv = targetLevel - 1;
                if (fontLv === lv) {
                } else if (fontLv > lv) {
                    if (fontLv >= 0) {
                        let str = `未掌握前置技能 ${familyId} lv:${fontLv + 1}`;
                        Logger.toastProduct(str, player, ColorStr.red);
                    } else {
                        let str = `无法学习重复技能`;
                        Logger.toastProduct(str, player, ColorStr.red);
                    }
                    return false;
                } else if (fontLv < lv) {
                    let str = `无法学习重复技能`;
                    Logger.toastProduct(str, player, ColorStr.red);
                    return false;
                }
            }

            // 如果有其他本家族技能 移除掉旧技能
            const oldAbilityId = ret.id
            if (oldAbilityId) {
                let hotKey = 'def';
                const oldAbilityData = DataRouter.getAbilityDataById(oldAbilityId);
                if (oldAbilityData) {
                    // todo 【需要被回退】 用key
                    hotKey = oldAbilityData.Hotkey;
                }
                const nextAbilityId = DataRouterUtil.getNextAbilityIdByFamilyId(oldAbilityId, hotKey);
                if (nextAbilityId) {
                    this.loseAbility(unit, oldAbilityId);
                    this.learnAbility(unit, nextAbilityId, 1);
                    return true;
                } else {
                    Logger.toastProduct(`技能已经最大等级`, player)
                    return false;
                }
                return true;
            } else {
                const firstHotKey = this.getFirstNullHotKey(unit);
                const newAbilityId = DataRouterUtil.getAbilityIdByFamilyIdHotKey(familyId, firstHotKey);
                const learnSkillFailed = this.recordAbility(unit, newAbilityId, oldAbilityId);
                switch (learnSkillFailed) {
                    case LearnSkillFailed.autoLearn:{
                        Logger.toastProduct(`您已经学会了这个技能`, player)
                        return false;
                    }
                    case LearnSkillFailed.overMax:{
                        const skillHotKey: string[] = Configer.getFinal(FinalKey.skillHotKeys);
                        const maxAbilityNum = skillHotKey.length;
                        Logger.toastProduct(`您最多只能学习${maxAbilityNum}个技能!`, player);
                        return false;
                    }
                    case LearnSkillFailed.isNull:{
                        Logger.toastError(`学习技能Id不能为空, 请联系作者!`);
                        return false;
                    }
                }
                this.learnAbility(unit, newAbilityId, 1);
                return true;
            }
        } else {
            Logger.toastError(`请传入正确的技能家族`);
        }
    }
    getFirstNullAbilitysIndex(unit: UnitModel) {
        const arr = unit.data[UnitDataKey.abilitys]
        // const maxAbilityNum: number = Configer.getConfig(ConfigKey.maxAbilityNum);
        const hotKeys: string[] = Configer.getFinal(FinalKey.skillHotKeys);
        for (let i = 0; i < hotKeys.length; i++) {
            const key = hotKeys[i];
            if (arr[key]) {
            } else {
                return i
            }
        }
        return -1
    }
    getFirstNullHotKey(unit: UnitModel) {
        const len = this.getFirstNullAbilitysIndex(unit);
        const hotKeys: string[] = Configer.getFinal(FinalKey.skillHotKeys);
        const key = hotKeys[len];
        return key;
    }
    setCoolNum(unit: UnitModel, abilityId: string, coolNum: number) {
        const arr = unit.data[UnitDataKey.abilitys];
        CodeUtil.mapObj(arr, (key, abilityJson) => {
            const tempId = abilityJson.id;
            if (abilityId === tempId) {
                abilityJson.cd = coolNum;
            }
        })

    }
    learnAbility (unit: UnitModel, abilityId: string, level: number = 1, add: boolean = true) {
        if (!CodeUtil.isNullOrZero(abilityId)) {
            const arr = unit.data[UnitDataKey.abilitys];
            // let cool = DataRouter.getAbilityDataById(abilityId)?.Cool;
            // cool = cool ? cool : 0;
            const abilityInfo: AbilityJson = { id: abilityId, lv: 1, cd: 0 };

            // todo 【需要被回退】 用key
            const key = DataRouter.getAbilityDataById(abilityId)?.Hotkey;
            if (!CodeUtil.isNullOrZero(key)) {
                arr[`${key}`] = abilityInfo;
            } else {
                arr[`${abilityId}`] = abilityInfo;
            }
            if (add) {
                // Logger.toastError(abilityId + '学习成功');
                unit.addAbility(abilityId)
            }
        }
    }
    // hasAbility (unit: UnitModel, abilityId: string) {
    //     const arr = unit.data[UnitDataKey.abilitys];
    //     const len: number = Configer.getConfig(ConfigKey.maxAbilityNum);
    //     for (let i = len - 1; i >= 0; i--) {
    //         const abilityInfo = arr[i];
    //         if (abilityInfo) {
    //             const tempAbilityId = abilityInfo.id;
    //             if (tempAbilityId === abilityId) {
    //                 return true;
    //             }
    //         }
    //     }
    //     return false;
    // }
    // 如果当前技能的前置技能存在，则计算最大长度时不计算前置技能；
    recordAbility(unit: UnitModel, abilityId: string, oldAbilityId?: string): LearnSkillFailed {
        let ret;
        const skillHotKey: string[] = Configer.getFinal(FinalKey.skillHotKeys);
        let maxNum = skillHotKey.length;
        if (!CodeUtil.isNullOrZero(oldAbilityId)) {
            maxNum = maxNum + 1;
        }
        // 这里可以使用len是因为如果数组中有空位  说明仍然可以学技能 不影响结果
        const index = this.getFirstNullAbilitysIndex(unit);

        if (index && index >= 0 && index < maxNum) {
        } else {
            ret = LearnSkillFailed.overMax;
        }

        if (abilityId) {
        } else {
            if (ret) {
                return ret;
            }
            return LearnSkillFailed.isNull;
        }
        const hasAbility = unit.hasAbility(abilityId)
        if (hasAbility) {
            return LearnSkillFailed.autoLearn;
        }
        return  ret;
    }
    reflushAbilityCool = (unit: UnitModel, subNum: number) => {
        if (unit?.isValid()) {
        } else {
            return;
        }
        const arr = unit.data[UnitDataKey.abilitys];
        CodeUtil.mapObj(arr, (key, abilityInfo) => {
            if (abilityInfo) {
                const id = abilityInfo.id
                let cl = abilityInfo.cd;
                if (cl) {
                    if (cl && cl > subNum) {
                        abilityInfo.cd = MathUtil.toFixed(cl - subNum, 2);
                    } else if (cl === subNum) {
                        abilityInfo.cd = 0;
                        unit.replaceAbility(id, id)
                    }
                }
            }
        })
    }
    initAbilityAttr(unit: UnitModel) {
        const abilityList = unit.template?.abilitys;
        const abilityArr = CodeUtil.getArrBySplit(abilityList);
        if (abilityArr) {
            for (let i = 0; i < abilityArr.length; i++) {
                const abilityId = abilityArr[i];
                const firstIndex = this.getFirstNullAbilitysIndex(unit);
                if (firstIndex && firstIndex >= 0) {
                    this.learnAbility(unit, abilityId, 1);
                }
            }
        }
    }
    chooseLoseAbility (unit: UnitModel, successCallBack: () => void) {
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        const abilitys: { [key: string]: AbilityJson } = unit.data[UnitDataKey.abilitys];
        if (abilitys) {
        } else {
            Logger.toastProduct(`该单位无法遗忘技能`, player)
        }
        const arr: DialogControllerOpt[] = [];
        // const maxAbilityNum: number = Configer.getConfig(ConfigKey.maxAbilityNum);
        if (abilitys) {
            CodeUtil.mapObj(abilitys, (key, abilityInfo) => {
                if (abilityInfo) {
                    const abilityId = abilityInfo.id;
                    if (unit.hasAbility(abilityId)) {
                        const abilityData = DataRouter.getAbilityDataById(abilityId)
                        if (abilityData) {
                            const name = abilityData.Name;
                            const id = `遗忘 ${name}`;
                            const callBack = (self: ControllerOpt) => {
                                this.loseAbility(unit, abilityId);
                                successCallBack();
                            }
                            const opt: DialogControllerOpt = new DialogControllerOpt(id, callBack);
                            arr.push(opt);
                        }
                    }
                }
            })
            const callBack = (self: ControllerOpt) => {
            }
            const opt: DialogControllerOpt = new DialogControllerOpt('取消', callBack);
            arr.push(opt);
            if (arr.length > 0 && player) {
                DialogController.getInstance().showDialog({ player, dialogName: '删除技能', optList: arr });
                return;
            }
        }
        Logger.toastProduct(`您目前没有技能`, player)
    }
    loseAbility(unit: UnitModel, abilityId: string) {
        unit.removeAbility(abilityId)
        let index = 0;
        const arr = unit.data[UnitDataKey.abilitys];
        // const maxAbilityNum: number = Configer.getConfig(ConfigKey.maxAbilityNum);
        CodeUtil.mapObj(arr, (key, abilityInfo) => {
            if (abilityInfo) {
                const tempAbilityId = abilityInfo.id;
                if (tempAbilityId === abilityId) {
                    arr[key] = undefined;
                }
            }
        })

        const abilityData = DataRouter.getAbilityDataById(abilityId);
        if (abilityData) {
        } else {
            Logger.toastError(`正在遗忘一个不存在的技能: ${abilityId}`)
            return index;
        }
        const effectIds = abilityData.effects;
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        if (effectIds) {
            const effectIdArr = CodeUtil.getArrBySplit(effectIds);
            for (let i = 0; i < effectIdArr.length; i++) {
                const effectId = effectIdArr[i];
                const request: BroadcastRequest = { broadcastType: BroadcastType.clearSummoneByEffectId, controllerNo: ControllerNo.UnitController, data: { player: player, effectId: effectId } }
                ControllerBroadcast.getInstance().broadcast(request);
            }
        }
        return index;
    }
    getBuffs (unit: UnitModel): BuffInfo[] {
        const buffInfos: BuffInfo[] = [];
        const handleId = unit?.getHandleId();
        if (handleId) {
            const effects = this.attributeUnitMaps[handleId];
            CodeUtil.mapObj(effects, (effectId, time) => {
                const effectData = DataRouter.getEffectByEffectId(effectId);
                if (effectData) {
                    const magic_effect = effectData.magic_effect;
                    const name = effectData.name;
                    const des = effectData.txt;
                    if (magic_effect) {
                        const buffInfo: BuffInfo = { name: name, image: magic_effect, des: des, time: time };
                        buffInfos.push(buffInfo);
                    }
                }
            })
        }
        return buffInfos;
    }
    caluAbilityAttributes(unit: UnitModel): Attrs {
        let newAddAttrs = new UnitAttribute();
        const abilityAttrs = unit.data[UnitDataKey.abilityAttribute];
        const enmuAttr = Configer.getConfig(ConfigKey.trackAttr) as string;
        CodeUtil.mapObj(abilityAttrs, (effectId, attribute) => {
            if (attribute) {
                const ret = this.clearUnValidAttribute(unit, effectId);
                if (ret) {
                    return;
                }
                Logger.toastAttr(`技能${effectId}:${AttributeEnum[enmuAttr]}: ${attribute[enmuAttr]}`)
                newAddAttrs = Util.sumUnitAttribute(newAddAttrs, attribute, CaluType.add);
            }
        })

        let attrs: Attrs = { unitAttr: newAddAttrs, playerAttr: undefined };

        // DataRouter.mapAllAbilityData(
        //     (abilityData) => {
        //         const id = abilityData?.id;
        //         if (id) {
        //             const has = unit.hasAbility(id);
        //             if (has) {
        //                 const attrId = abilityData.attrId;
        //                 if (attrId) {
        //                     const attribute = DataRouterUtil.getAttrByAttrInterface(abilityData, 1);
        //                     attrs = Util.sumAttributes(attrs, attribute, CaluType.add);
        //                 }
        //             }
        //         }
        //     }
        // )

        return attrs;
    }
    clearUnValidAttribute(unit: UnitModel, effectId: string): boolean {
        const handleId = unit?.getHandleId();
        if (handleId) {
            const map = this.attributeUnitMaps[handleId];
            if (map) {
                const time = map[effectId];
                if (time && time <= 0) {
                    this.removeAbilityAttributes(unit, effectId);
                    return true;
                }
            }
        }
        return false;
    }
    removeFakeAbilityByEffect(unit: UnitModel, effectId: string) {
        const abilityEffectData = DataRouter.getEffectByEffectId(effectId);
        if (abilityEffectData) {
            const fakeAbilityId = abilityEffectData.addAbility;
            this.removeFakeAbility(unit, fakeAbilityId)

            const add_transformation = abilityEffectData.add_transformation;
            if (!CodeUtil.isNullOrZero(add_transformation)) {
                const defaultModel = unit.data[UnitDataKey.modelDefaultPath];
                const modelPath = unit.data[UnitDataKey.modelPath];
                if (!CodeUtil.isNullOrZero(modelPath)) {
                    if (!CodeUtil.isNullOrZero(defaultModel)) {
                        unit.data[UnitDataKey.modelPath] = undefined;
                        unit.setModelPath(defaultModel);
                        const owner = PlayerFactory.getInstance().getUnitOwner(unit);
                        const hero = GlobalEnv.getHero(owner);
                        if (hero === unit) {
                            const goodsRequest: BroadcastRequest = { broadcastType: BroadcastType.mapGoodsAddEffect, controllerNo: ControllerNo.GoodController, data: { player: owner } }
                            ControllerBroadcast.getInstance().broadcast(goodsRequest);
                        }
                    } else {
                        Logger.toastError(`单位 ${unit.name} 使用了变身技能但是没有设置默认模型, 请联系作者修改`)
                    }
                }
            }
        } else {
            Logger.toastError(`不能移除不存在的伪装技能 ${effectId}`)
        }
    }
    removeFakeAbility(unit: UnitModel, abilityId: string) {
        if (abilityId) {
            const hasAbility = unit.hasAbility(abilityId);
            if (hasAbility) {
                unit.removeAbility(abilityId);
            } else {
            }
        }
    }
    addFakeAbilityByEffectId(unit: UnitModel, effectId: string) {
        const abilityEffectData = DataRouter.getEffectByEffectId(effectId);
        if (abilityEffectData) {
            const fakeAbilityId = abilityEffectData.addAbility;
            this.addFakeAbility(unit, fakeAbilityId);
            const add_transformation = abilityEffectData.add_transformation;
            if (add_transformation) {
                unit.setModelPath(add_transformation);
                const owner = PlayerFactory.getInstance().getUnitOwner(unit);
                const hero = GlobalEnv.getHero(owner);
                if (hero === unit) {
                    const goodsRequest: BroadcastRequest = { broadcastType: BroadcastType.mapGoodsAddEffect, controllerNo: ControllerNo.GoodController, data: { player: owner } }
                    ControllerBroadcast.getInstance().broadcast(goodsRequest);
                }
            }
        } else {
            Logger.toastError(`不能添加不存在的伪装技能 ${effectId}`)
        }
    }
    addFakeAbility(unit: UnitModel, abilityId: string) {
        if (abilityId) {
            const hasAbility = unit.hasAbility(abilityId);
            if (hasAbility) {
            } else {
                unit.addAbility(abilityId);
            }
        }
    }

    reflushAbilityAttributes = () => {
        CodeUtil.mapObj(this.attributeUnitMaps,
            (handleId, map) => {
                const unit: UnitModel = ModelFactory.getInstance().getModel(handleId, ModelType.unit) as UnitModel;
                if (unit?.isValid()) {
                    CodeUtil.mapObj(map,
                        (effectId, time) => {
                            if (time && time >= 0) {
                                const newTime = time - 1;
                                map[effectId] = newTime;
                                if (newTime < 0) {
                                    const request: BroadcastRequest = { broadcastType: BroadcastType.addCaluTaskByUnit, controllerNo: ControllerNo.UnitController, data: { unit: unit, caluAttrStr: CaluAttrStr.ability } }
                                    ControllerBroadcast.getInstance().broadcast(request);
                                }
                            }
                        }
                    )
                }
            }
        )
    }

    reflushAbilityLocks = () => {
        CodeUtil.mapObj(this.abilityLockUnitMaps,
            (handleId, map) => {
                const unit: UnitModel = ModelFactory.getInstance().getModel(handleId, ModelType.unit) as UnitModel;
                if (unit?.isValid()) {
                    CodeUtil.mapObj(map,
                        (effectId, time) => {
                            if (time && time >= 0) {
                                const newTime = time - 1;
                                map[effectId] = newTime;
                            } else {
                                map[effectId] = undefined;
                            }
                        }
                    )
                }
            }
        )
    }

    addAbilityAttributes = (unit: UnitModel, effectId: string, duration: number, attribute?: UnitAttribute) => {
        const attributeMap = unit.data[UnitDataKey.abilityAttribute];
        if (attribute) {
            attributeMap[effectId] = attribute;
        }
        this.addFakeAbilityByEffectId(unit, effectId);

        const foreverPeriodic = Configer.getFinal(FinalKey.foreverPeriodic) as number;

        if (duration === foreverPeriodic) {
        } else {
            const handleId = unit?.getHandleId();
            if (handleId) {
                let map = this.attributeUnitMaps[handleId];
                if (map) {
                } else {
                    this.attributeUnitMaps[handleId] = {};
                    map = this.attributeUnitMaps[handleId];
                }
                map[effectId] = duration;
            }
        }
    }
    getAbilityJsonByIndex (unit: UnitModel, key: string) {
        const abilitys = unit.data[UnitDataKey.abilitys];
        // print(JSON.stringify(abilitys));
        const json = abilitys[`${key}`];
        return json
    }
    getAbilitys(unit: UnitModel) {
        const abilitys = unit?.data[UnitDataKey.abilitys];
        if (abilitys) {
            return abilitys
        }
        return {}
    }
    getAbilityAttributes(unit: UnitModel, effectId: string) {
        const abilityAttrs = unit.data[UnitDataKey.abilityAttribute];
        return abilityAttrs[effectId]
    }
    removeAbilityAttributes(unit: UnitModel, effectId: string) {
        const handleId = unit?.getHandleId();
        if (handleId) {
            const attributeMap = unit.data[UnitDataKey.abilityAttribute];
            this.removeFakeAbilityByEffect(unit, effectId);
            attributeMap[effectId] = undefined;
            const map = this.attributeUnitMaps[handleId];
            if (map) {
                map[effectId] = undefined
            }
            // Logger.toastError(`移除${effectId}`)
            // const request: BroadcastRequest = { broadcastType: BroadcastType.addCaluTaskByUnit, controllerNo: ControllerNo.UnitController, data: { unit: unit, caluAttrStr: CaluAttrStr.ability } }
            // ControllerBroadcast.getInstance().broadcast(request);
        }
    }
    private addFrequency (unit: UnitModel, effectId: string) {
        const frequencys = unit.data[UnitDataKey.abilityFrequency];
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        if (frequencys) {
            const frequency = frequencys[effectId];
            Logger.toastSkill(`当前频率:${frequency}`, player)
            const newFrequency = frequency + 1;
            Logger.toastSkill(`新频率:${newFrequency}`, player)
            frequencys[effectId] = newFrequency;
            Logger.toastSkill(`技能频率加1`, player)
        }
    }
    private resetFrequency (unit: UnitModel, effectId: string) {
        const frequencys = unit.data[UnitDataKey.abilityFrequency];
        const newFrequency = 0;
        frequencys[effectId] = newFrequency;
    }
    getFrequency (unit: UnitModel, effectId: string) {
        const frequencys = unit.data[UnitDataKey.abilityFrequency];
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        Logger.toastSkill(`获取effectId频率:${effectId}`, player)
        if (frequencys) {
            const frequency = frequencys[effectId]
            if (frequency) {
                return frequency;
            } else {
                frequencys[effectId] = 0;
                return 0;
            }
        } else {
            unit.data[UnitDataKey.abilityFrequency][effectId] = 0;
            return 0;
        }
    }
    checkFrequency (unit: UnitModel, effectId: string, targetNum: number) {
        const frequency = this.getFrequency(unit, effectId);
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        Logger.toastSkill(`当前次数 :${frequency}`, player)
        Logger.toastSkill(`触发技能所需次数 :${targetNum}`, player)
        if (frequency < targetNum - 1) {
            this.addFrequency(unit, effectId);
            Logger.toastSkill(`不符合条件，等待下次触发`, player)
            return false;
        } else {
            this.resetFrequency(unit, effectId);
            Logger.toastSkill(`符合条件，发动效果！`, player)
            return true;
        }
    }
    getAbilityBiggestFamilyLevel(unit: UnitModel, familyId: string) {
        const abilitys = unit.data[UnitDataKey.abilitys];
        const player = PlayerFactory.getInstance().getUnitOwner(unit);
        let bigest = 0;
        if (abilitys) {
            CodeUtil.mapObj(abilitys, (hotKey, ability) => {
                if (ability) {
                } else {
                    return false;
                }
                const abilityId = ability.id;
                const abilityData = DataRouter.getAbilityDataById(abilityId);
                Logger.toastSkill(`学习技能Id：${abilityId}`, player)
                if (abilityData?.family_tpye ===  familyId) {
                    Logger.toastSkill(`技能家族：${abilityData.family_tpye}`, player)
                    const familyLevel = abilityData.family_level;
                    Logger.toastSkill(`技能家族等级：${abilityData.family_level}`, player)
                    if (familyLevel > bigest) {
                        bigest = familyLevel;
                    }
                }
            })
        }
        return bigest;
    }
    copyAbilitys(oldUnit: UnitModel, newUnit: UnitModel) {
        const abilitys = oldUnit.data[UnitDataKey.abilitys];
        // const maxAbilityNum: number = Configer.getConfig(ConfigKey.maxAbilityNum);
        if (abilitys) {
            CodeUtil.mapObj(abilitys, (hotKey, ability) => {
                if (ability) {
                } else {
                    return false;
                }
                const abilityId = ability.id;
                newUnit.addAbility(abilityId)
            })
            newUnit.data[UnitDataKey.abilitys] = abilitys;
        }
    }
    unitDeadRemove(unit: UnitModel) {
        const handleId = unit.getHandleId();
        if (handleId) {
            this.attributeUnitMaps[handleId] = undefined
        }
    }
    notify(request: BroadcastRequest): BroadcastResponse {
        const ret: BroadcastResponse = { controllerNo: this.getControllerNo(), data: {}, status: BroadcastResponseStatus.success };
        const type = request.broadcastType;
        const data = request.data;
        switch (type) {
            case BroadcastType.serialize: {
                const player: PlayerModel = data.player;
                const serializeBody: SerializeBody = this.serialize(player);
                ret.data = { serializeBody };
                break;
            }
            case BroadcastType.caluAbilityAttributes: {
                const unit: UnitModel = data.unit;
                const attribute = this.caluAbilityAttributes(unit);
                ret.data = { attribute };
                break;
            }
            case BroadcastType.copyAbilitys: {
                const unit: UnitModel = data.unit;
                const newUnit: UnitModel = data.newUnit;
                this.copyAbilitys(unit, newUnit);
                break;
            }
            case BroadcastType.getAbilityBiggestFamilyLevel: {
                const unit: UnitModel = data.unit;
                const familyId: string = data.familyId;
                const familyLevel = this.getAbilityBiggestFamilyLevel(unit, familyId);
                ret.data = { familyLevel };
                break;
            }
            case BroadcastType.removeSkill: {
                const unit: UnitModel = data.unit;
                const abilityId: string = data.abilityId;
                this.loseAbility(unit, abilityId);
                break;
            }
            case BroadcastType.learnSkill: {
                const unit: UnitModel = data.unit;
                const abilityId: string = data.abilityId;
                const success = this.learnAbilityCheck(unit, abilityId);
                ret.data = { success }
                break;
            }
            case BroadcastType.learnSkillByFamilyLv: {
                const unit: UnitModel = data.unit;
                const familyId: string = data.familyId;
                const level: number = data.level;
                const success = this.learnAbilityByFamilyIdCheck(unit, familyId, level);
                ret.data = { success }
                break;
            }
            case BroadcastType.removeSkillByFamilyLv: {
                const unit: UnitModel = data.unit;
                const familyId: string = data.familyId;
                const level: number = data.level;
                this.loseAbilityByFamilyIdCheck(unit, familyId, level);
                break;
            }
            case BroadcastType.deleteAbilityAttr: {
                const unit: UnitModel = data.unit;
                this.unitDeadRemove(unit);
                break;
            }
            case BroadcastType.reflushCool: {
                const unit: UnitModel = data.unit;
                this.reflushAbilityCool(unit, 0.1);
                break;
            }
            case BroadcastType.initAbilityAttr: {
                const unit: UnitModel = data.unit;
                this.initAbilityAttr(unit);
                break;
            }
            default :
                ret.status = BroadcastResponseStatus.failed;
                break;
        }
        return ret;
    }
    serialize(player: PlayerModel): AbilitySerializeBody {
        const abilitySerializeBody: AbilitySerializeBody = player.data[PlayerDataKey.storeCurrent][ControllerNo.AbilityController];

        const unit = GlobalEnv.getHero(player);
        const abilitys = this.getAbilitys(unit);
        const archiveIndex = player.data[PlayerDataKey.archiveIndex];
        this.mapAbilitySerialize(archiveIndex, SerializeLoadType.current_global, (key, index, hotKey) => {
            abilitySerializeBody[key] = abilitys[hotKey];
        })

        return abilitySerializeBody;
    }
    addAbilityLock(unit: UnitModel, effectData: AbilityEffectData) {
        let lockTime = 0;
        let success = true;

        const effectId = effectData.id;

        const handleId = unit?.getHandleId();
        if (handleId) {
            let map = this.abilityLockUnitMaps[handleId];
            if (map) {
            } else {
                this.abilityLockUnitMaps[handleId] = {};
                map = this.abilityLockUnitMaps[handleId];
            }


            if (CodeUtil.isNullOrZero(effectData.cool)) {
            } else {
                if (CodeUtil.isNullOrZero(map[effectId])) {
                    lockTime = lockTime + effectData.cool;
                    map[effectId] = lockTime;
                } else {
                    success = false;
                }
            }

        }

        return success;
    }

    mapAbilitySerialize = (index: number, bAll: SerializeLoadType, callBack: (key: string, index: number, hotKey: string) => void) => {
        const archiveFun = (archiveIndex: number) => {
            const skillHotKey: string[] = Configer.getFinal(FinalKey.skillHotKeys);
            const storeKeys = ['qa', 'wa', 'ea', 'ra', 'ta', 'ya', 'ua'];
            for (let i = 0; i < storeKeys.length; i++) {
                const key = `${storeKeys[i]}_${archiveIndex}`;
                const hotKey = skillHotKey[i];
                callBack(key, 0, hotKey);
            }
        }

        switch (bAll) {
            case SerializeLoadType.current_global:
            case SerializeLoadType.current_archive: {
                const archiveIndex = index;
                archiveFun(archiveIndex);
                break;
            }
            case SerializeLoadType.all_global:
            case SerializeLoadType.all_archive: {
                const maxArchiveNum = Configer.getConfig(ConfigKey.maxArchiveNum);
                for (let i = 0; i < maxArchiveNum; i++) {
                    const tempIndex = i + 1;
                    archiveFun(tempIndex);
                }
                break;
            }
        }
    }
}